function sensorLevelClassifyFrequency(subject, toi, foi, lambda, class1, class2, condition)
    % Performs classification in the frequency domain
    
    % Loads data from subject.subjectDir/subject.subjID_data.mat
    % subject: subject specific struct, which should at least contain the fields subjID, subjectDir and MEGChannels (all MEG channels but the ones that are rejected)
	% toi: beginTime:stepsize:endTime
	% foi: beginFreq:stepsize:endFreq
	% lambda: the elastic net lambda parameter
	% class1 and class2: classes to perform classification on
	% Performs frequency analysis for the classes for which this is not done yet and stores that data in subject.subjectDir/subject.subjID_freqAnalysis_className_foi_min(foi)-max(foi)-by-(foi(2)-foi(1))_toi_min(toi)-max(toi)-by-(toi(2)-toi(1)).mat
	% When the frequency analysis has been performed before, that data is loaded from the above mentioned file.
	% Final classification data is stored in subject.subjectDir/subject.subjID_sensorLevelFreq_class1-class2_foi_min(foi)-max(foi)-by-(foi(2)-foi(1))_toi_min(toi)-max(toi)-by-(toi(2)-toi(1))_lambda_lambda.mat
	
    eval(['load ', subject.subjectDir, '/', subject.subjID, '_', condition, '_data.mat data;']);

    if strcmp(subject.subjID,'P01')
         nTrial_face = find(data.trialinfo == 201);
         nTrial_scene = find(data.trialinfo == 202);
         nTrial_body = find(data.trialinfo == 203);
         nTrial_tool = find(data.trialinfo == 204);
         nTrial_word = find(data.trialinfo == 205);
    else
        if strcmp(condition, 'noCond') || strcmp(condition, 'lum_spat')
            nTrial_face = find(data.trialinfo == 21);
            nTrial_scene = find(data.trialinfo == 22);
            nTrial_body = find(data.trialinfo == 23);
            nTrial_tool = find(data.trialinfo == 24);
            nTrial_word = find(data.trialinfo == 25);
        elseif strcmp(condition, 'lum')
            nTrial_face = find(data.trialinfo == 31);
            nTrial_scene = find(data.trialinfo == 32);
            nTrial_body = find(data.trialinfo == 33);
            nTrial_tool = find(data.trialinfo == 34);
            nTrial_word = find(data.trialinfo == 35);
        else
            error('ERROR: Unknown condition identifier. Please specify ''lum'' or ''lum_spat''');
        end
    end

    if eval(['~isempty(nTrial_', class1, ') && ~isempty(nTrial_', class2, ')'])

        [faceTrl sceneTrl bodyTrl toolTrl wordTrl] = deal([]);

        if strcmp(subject.subjID, 'P01')
            for i = 1 : length(data.trialinfo)
                if data.trialinfo(i) == 201 %faces
                    faceTrl = [faceTrl i];
                elseif data.trialinfo(i) == 202 %scenes
                    sceneTrl = [sceneTrl i];
                elseif data.trialinfo(i) == 203 %bodies
                    bodyTrl = [bodyTrl i];
                elseif data.trialinfo(i) == 204 %tools
                    toolTrl = [toolTrl i];
                elseif data.trialinfo(i) == 205 %words
                    wordTrl = [wordTrl i];
                else
                    error('ERROR: Invalid category trigger code.');
                end
            end
        elseif strcmp(condition, 'coCond') || strcmp(condition, 'lum_spat')
            for i = 1 : length(data.trialinfo)
                if data.trialinfo(i) == 21 %faces
                    faceTrl = [faceTrl i];
                elseif data.trialinfo(i) == 22 %scenes
                    sceneTrl = [sceneTrl i];
                elseif data.trialinfo(i) == 23 %bodies
                    bodyTrl = [bodyTrl i];
                elseif data.trialinfo(i) == 24 %tools
                    toolTrl = [toolTrl i];
                elseif data.trialinfo(i) == 25 %words
                    wordTrl = [wordTrl i];
                else
                    error('ERROR: Invalid category trigger code.');
                end
            end
        elseif strcmp(condition, 'lum')
            for i = 1 : length(data.trialinfo)
                if data.trialinfo(i) == 31 %faces
                    faceTrl = [faceTrl i];
                elseif data.trialinfo(i) == 32 %scenes
                    sceneTrl = [sceneTrl i];
                elseif data.trialinfo(i) == 33 %bodies
                    bodyTrl = [bodyTrl i];
                elseif data.trialinfo(i) == 34 %tools
                    toolTrl = [toolTrl i];
                elseif data.trialinfo(i) == 35 %words
                    wordTrl = [wordTrl i];
                else
                    error('ERROR: Invalid category trigger code.');
                end
            end
        else
            error('ERROR: Unknown condition identifier. Please specify ''lum'' or ''lum_spat''');
        end
        
        display(sprintf('Number of face trials is %i', size(faceTrl,2)));
        display(sprintf('Number of scene trials is %i', size(sceneTrl,2)));
        display(sprintf('Number of body trials is %i', size(bodyTrl,2)));
        display(sprintf('Number of tool trials is %i', size(toolTrl,2)));
        display(sprintf('Number of word trials is %i', size(wordTrl,2)));
        display(sprintf('\nTotal number of valid trials is %i', size(faceTrl,2) + size(sceneTrl,2) + size(bodyTrl,2) + size(toolTrl,2) + size(wordTrl,2)));

        if (size(faceTrl,2) + size(sceneTrl,2) + size(bodyTrl,2) + size(toolTrl,2) + size(wordTrl,2) ~= length(data.trialinfo)) %error in division
            error('ERROR: Sum of all defined trials is not equal to the total number of trials.');
        end

        className = {class1, class2};
        for i = 1:2
            lockfile = sprintf('touch %s/%s_%s_freqAnalysis_%s_foi_%i-%i,-by-%i_toi_%i-%i-by-%i.lock', subject.subjectDir, subject.subjID, condition, className{i}, min(foi), max(foi), foi(2)-foi(1), min(toi), max(toi), toi(2)-toi(1));
            
            if exist([subject.subjectDir, '/', subject.subjID, '_', condition, '_freqAnalysis_', className{i}, '_foi_', num2str(min(foi)), '-', num2str(max(foi)), '-by-', num2str(foi(2)-foi(1)), '_toi_', num2str(min(toi)), '-', num2str(max(toi)), '-by-', num2str(toi(2)-toi(1)), '.mat'], 'file')
                % the file is either being saved or already saved
                while exist(lockfile, 'file')
                    %Wait for the lockfile to be gone before the file can be
                    %accessed
                    display('Waiting for file release')
                end
                % if the lockfile is gone, the saved file can be loaded
                load([subject.subjectDir, '/', subject.subjID, '_', condition, '_freqAnalysis_', className{i},'_foi_', num2str(min(foi)), '-', num2str(max(foi)), '-by-', num2str(foi(2)-foi(1)), '_toi_', num2str(min(toi)), '-', num2str(max(toi)), '-by-', num2str(toi(2)-toi(1)), '.mat'])
            else
                % in all other cases, which would include situations in which
                % by now the file is already being saved, calculate from the
                % scratch
                cfg = [];
                cfg.channel = subject.MEGChannels;
                eval(['cfg.trials = ', className{i}, 'Trl;']);
                cfg.method = 'mtmconvol';
                cfg.output = 'pow';
                cfg.keeptrials = 'yes';
                cfg.taper = 'hanning';
                cfg.foi = foi;
                cfg.tapsmofrq = ones(1,size(cfg.foi,2)); % want variable smoothing?
                cfg.t_ftimwin = 0.5*ones(length(cfg.foi)); %or nCyclesPerWindow./cfg.foi
                cfg.toi = toi;
                cfg.pad = 'maxperlen';
                eval(['data_freqAnalysis_', className{i}, ' = ft_freqanalysis(cfg, data);']);

                % only save when the file is not yet written, otherwise use
                % the just calculated data but don't save, as this is
                % already being done. Only occurs when a thread starts
                % saving while this thread is calculating.
                if ~exist([subject.subjectDir, '/', subject.subjID, '_', condition, '_freqAnalysis_', className{i}, '_foi_', num2str(min(foi)), '-', num2str(max(foi)), '-by-', num2str(foi(2)-foi(1)), '_toi_', num2str(min(toi)), '-', num2str(max(toi)), '-by-', num2str(toi(2)-toi(1)), '.mat'], 'file') && ~exist(lockfile, 'file')
                    % create a save lock: only start saving when there is no
                    % create save lock. No other file should be able to access
                    % the file (save or load) when the save lock file exists
                    system(sprintf('touch %s', lockfile));
                    save([subject.subjectDir, '/', subject.subjID, '_', condition, '_freqAnalysis_', className{i}, '_foi_', num2str(min(foi)), '-', num2str(max(foi)), '-by-', num2str(foi(2)-foi(1)), '_toi_', num2str(min(toi)), '-', num2str(max(toi)), '-by-', num2str(toi(2)-toi(1)), '.mat'],'data_freqAnalysis_*', '-v7.3')
                    system(sprintf('rm %s', lockfile));
                    % delete save lock. File is accessible again.
                end
            end
        end

        eval(['cond1data = data_freqAnalysis_', class1, ';']);
        eval(['cond2data = data_freqAnalysis_', class2, ';']);

        if(isempty(find(isnan(cond1data.powspctrm), 1))) && (isempty(find(isnan(cond2data.powspctrm), 1))) %if there are no NaNs in the frequency data
 
            % cross-validation
            cfg             = [];
            cfg.statistic   = 'stat'; %to work around some hack that is the only thing that expects a field like this??
            cfg.layout      = 'CTF275.lay';
            cfg.method      = 'crossvalidate';
            cfg.channel     = subject.MEGChannels; %default is all, but not all is useful, EOG should be excluded (or maybe it is already excluded in some easrlier stage)
            %cfg.mva         = {ft_mv_standardizer ft_mv_svm};
            cfg.mva         = {ft_mv_standardizer ft_mv_glmnet('lambda', lambda)}; %old lambda 0.01, best lambda 0.0005
            cfg.design      = [ones(size(cond1data.powspctrm, 1),1); 2*ones(size(cond2data.powspctrm, 1),1)]';
            eval(['freqStat_', class1, '_', class2, ' = ft_freqstatistics(cfg,cond1data,cond2data);']);
            save([subject.subjectDir, '/', subject.subjID, '_', condition, '_sensorLevelFreq_', class1, '-', class2, '_foi_', num2str(min(foi)), '-', num2str(max(foi)), '-by-', num2str(foi(2)-foi(1)), '_toi_', num2str(min(toi)), '-', num2str(max(toi)), '-by-', num2str(toi(2)-toi(1)), '_lambda_', num2str(lambda), '.mat'],'freqStat_*', '*Trl', '-v7.3')

        else
            display(sprintf('Pair %s vs %s can not be classified for subject %s because of NaNs in the frequency data . Skipping.', class1, class2, subject.subjID));
        end
    else
        display(sprintf('Pair %s vs %s can not be classified for subject %s because of missing data. Skipping.', class1, class2, subject.subjID));
end